package com.liunian.channelhandler.handler;

import com.liunian.compress.Compressor;
import com.liunian.compress.CompressorFactory;
import com.liunian.serialize.Serializer;
import com.liunian.serialize.SerializerFactory;
import com.liunian.transport.message.MessageFormatConstant;
import com.liunian.transport.message.WrpcRequest;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;

/**
 * 1、魔术值magic 4B ----> wrpc.getBytes()
 * 2、当前的请求的版本version 1B ----> 1
 * 3、请求头的长度 header length 2B
 * 4、总的报文的长度 full length 4B
 * 5、序列化的长度 serialize 1B
 * 6、压缩的类型 compress 1B
 * 7、请求的类型 requestType 1B
 * 8、请求的Id requestId 8B
 *
 * body
 *
 * 出站时，第一个经过的 handler（处理器）
 */
@Slf4j
public class WrpcRequestEcoder extends MessageToByteEncoder<WrpcRequest> implements Serializable {
    /**
     * @param channelHandlerContext
     * @param wrpcRequest 我们原本的对象
     * @param byteBuf 要转换的形式 即报文
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, WrpcRequest wrpcRequest, ByteBuf byteBuf) throws Exception {
        // 4个字节的魔术值
        byteBuf.writeBytes(MessageFormatConstant.MAGIC);
        // 1个字节的版本号
        byteBuf.writeByte(MessageFormatConstant.VERSION);
        // 2个字节的头部长度
        byteBuf.writeShort(MessageFormatConstant.HEADER_LENGTH);
        // 总长度暂时不清楚，因为不知道body的长度 writeIndex(写指针)
        byteBuf.writerIndex(byteBuf.writerIndex() + MessageFormatConstant.FULL_FIELD_LENGTH);
        // 3个类型
        byteBuf.writeByte(wrpcRequest.getRequestType());
        byteBuf.writeByte(wrpcRequest.getSerializeType());
        byteBuf.writeByte(wrpcRequest.getCompressType());
        // 8字节的请求id
        byteBuf.writeLong(wrpcRequest.getRequestId());
        byteBuf.writeLong(wrpcRequest.getTimeStamp());
//        // 如果是心跳检测请求，就不处理请求体
//        if (wrpcRequest.getRequestType() == RequestType.HEART_BEAT.getId()) {
//            // 处理一下总长度，其实总长度 = header 长度
//            int writerIndex = byteBuf.writerIndex();
//            byteBuf.writerIndex(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGTH + MessageFormatConstant.HEADER_FIELD_LENGTH);
//            byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH);
//            byteBuf.writerIndex(writerIndex);
//            return;
//        }

        // 写入请求体（requestPayload）
        byte[] body = null;
        if (wrpcRequest.getRequestPayload() != null) {
            // 1、根据配置的序列化方式进行序列化
            // 怎么实现序列化 1、第一种方式---工具类 缺点是耦合性很高，如果以后想替换序列化的方式很难
            //             2、定义一个序列化器的接口，里面定义序列化和反序列化的抽象方法，具体的序列化和反序列化方式要去实现这个接口。以后新增序列化方式的时候去实现这个接口即可。
            Serializer serializer = SerializerFactory.getSerializer(wrpcRequest.getSerializeType()).getImpl();
            body = serializer.serialize(wrpcRequest.getRequestPayload());
            // 2、根据配置的压缩方式进行压缩
            Compressor compressor = CompressorFactory.getCompressor(wrpcRequest.getCompressType()).getImpl();
            body = compressor.compress(body);
        }

        if (body != null) {
            byteBuf.writeBytes(body);
        }
        int bodylength = body == null ? 0 : body.length;
        // 重新处理报文的总长度
        // 先保存当前的写指针的位置
        int writerIndex = byteBuf.writerIndex();
        // 将写指针的位置移动到总长度的位置上
        byteBuf.writerIndex(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGTH + MessageFormatConstant.HEADER_FIELD_LENGTH);
        byteBuf.writeInt(MessageFormatConstant.HEADER_LENGTH + bodylength);
        // 将写指针归位
        byteBuf.writerIndex(writerIndex);

        if (log.isDebugEnabled()) {
            log.debug("请求[{}]已经完成报文的编码", wrpcRequest.getRequestId());
        }

    }

}
